#ifdef SU1
#define _GLIBCXX_DEBUG
#endif

#include <algorithm>
#include <bitset>
#include <cassert>
#include <climits>
#include <cstring>
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cmath>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <stack>
#include <set>
#include <string>
#include <utility>
#include <vector>

using namespace std;

#define forn(i, n) for (int i = 0; i < int(n); i++)
#define forl(i, n) for (int i = 1; i <= int(n); i++)
#define ford(i, n) for (int i = int(n) - 1; i >= 0; i--)
#define fore(i, l, r) for (int i = int(l); i <= int(r); i++)
#define pb(a) push_back(a)
#define mp(x, y) make_pair((x), (y))
#define sz(a) (int) (a).size()
#define all(a) (a).begin(), (a).end()
#define ft first
#define sc second
#define x first
#define y second

template<typename X> inline X abs(const X& a) { return a < 0 ? -a : a; }
template<typename X> inline X sqr(const X& a) { return a * a; }

typedef long long li;
typedef long double ld;
typedef pair<int, int> pt;

const int INF = int(1e9);
const li INF64 = li(1e18);
const ld PI = acosl(ld(-1));
const ld EPS = 1e-9;

const int N = 1000 + 3;

struct edge
{
	int to, f, c, rev;
};

int n, m, s, t;
vector<edge> g[N];

void add (int from, int to, int cap)
{
	edge f = { to, 0, cap, sz(g[to]) };
	edge b = { from, 0, 0, sz(g[from]) };
	g[from].pb(f);
	g[to].pb(b);
}

inline bool read()
{
	if (scanf("%d%d%d%d", &n, &m, &s, &t) != 4) return false;
	if (n == 0 && m == 0 && s == 0 && t == 0) return false;
	--s, --t;
	forn(i, n) g[i].clear();
	forn(i, m)
	{
		int a, b;
		assert(scanf("%d%d", &a, &b) == 2);
		--a, --b;
		add(a, b, 1);
	}
	return true;
}

int level[N], q[N], tail, head, ptr[N];

inline bool bfs (int s, int t)
{
	forn(i, n) level[i] = INF;
	level[s] = 0;
	
	tail = head = 0;
	q[tail++] = s;
	
	while (tail != head)
	{
		int v = q[head++];
		
		forn(i, sz(g[v]))
		{
			const edge& e = g[v][i];
			if (e.f < e.c && level[e.to] > level[v] + 1)
			{
				level[e.to] = level[v] + 1;
				q[tail++] = e.to;
			}
		}
	}
	
	return level[t] < INF / 2;
}

bool dfs (int v, int t)
{
	if (v == t) return true;
	
	for (; ptr[v] < sz(g[v]); ptr[v]++)
	{
		edge& e = g[v][ptr[v]];
		if (e.f == e.c || level[v] + 1 != level[e.to]) continue;
		if (dfs(e.to, t))
		{
			e.f++;
			g[e.to][e.rev].f--;
			return true;
		}
	}
	return false;
}

int dinic (int s, int t)
{
	int ans = 0;
	while (true)
	{
		if (!bfs(s, t)) break;
		forn(i, n) ptr[i] = 0;
		while (true)
		{
			bool f = dfs(s, t);
			if (f == 0) break;
			ans++;
		}
	}
	return ans;
}

int used1[N], used2[N];

void dfs1 (int v)
{
	used1[v] = true;
	forn(i, sz(g[v]))
	{
		const edge& e = g[v][i];
		if (e.f < e.c && !used1[e.to]) dfs1(e.to);
	}
}

void go2 (int v)
{
	used2[v] = true;
	forn(i, sz(g[v]))
	{
		const edge& e = g[v][i];
		if (g[e.to][e.rev].f == 0 && g[e.to][e.rev].c == 1 && !used2[e.to]) go2(e.to);
	}
}

inline void solve()
{
	int flow = dinic(s, t);
	forn(i, n) used1[i] = used2[i] = false;
	dfs1(s);
	go2(t);
	
	int cnt = 0;
	
	forn(i, n) forn(j, sz(g[i]))
	{
		const edge& e = g[i][j];
		if (e.f == 0 && e.c == 1 && used1[e.to] && used2[i]) cnt++;
	}
	
	if (cnt > 0) flow++;
	
	cout << flow << ' ' << cnt << endl;
}

int main()
{
#ifdef SU1
	assert(freopen("input.txt", "rt", stdin));
//	assert(freopen("output.txt", "wt", stdout));
#endif

	cout << fixed << setprecision(10);
	cerr << fixed << setprecision(5);

	while (read())
		solve();
	
#ifdef SU1
	cerr << "=== TIME : " << clock() << " ===" << endl;
#endif
	return 0;
}
